package im.vinci.server.syncdb.service;

import im.vinci.server.common.exceptions.VinciException;
import im.vinci.server.common.exceptions.error.ErrorCode;
import im.vinci.server.feed.domain.FeedType;
import im.vinci.server.feed.domain.wrapper.PublishFeedRequest;
import im.vinci.server.feed.service.FeedService;
import im.vinci.server.syncdb.domain.ClientUserData;
import im.vinci.server.syncdb.domain.MusicFeedRelation;
import im.vinci.server.syncdb.domain.UserFavoriteMusic;
import im.vinci.server.syncdb.domain.wrapper.DownloadFavoriteMusicResponse;
import im.vinci.server.syncdb.persistence.MusicFeedRelationMapper;
import im.vinci.server.syncdb.persistence.UserFavoriteMusicOperator;
import im.vinci.server.user.domain.UserSettings;
import im.vinci.server.user.service.UserCountService;
import im.vinci.server.user.service.UserLoginAndBindDeviceService;
import im.vinci.server.utils.BizTemplate;
import im.vinci.server.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * 用户收藏音乐service
 * Created by mingjie on 16/10/21.
 */
@Service
public class UserFavoriteMusicOperateService {

    @Autowired
    private UserFavoriteMusicOperator favoriteDataOperator;

    @Autowired
    private MusicFeedRelationMapper musicFeedRelationMapper;

    @Autowired
    private UserCountService userCountService;

    @Autowired
    private FeedService feedService;

    @Autowired
    private UserLoginAndBindDeviceService userLoginAndBindDeviceService;

    public DownloadFavoriteMusicResponse getUserData(long userId, int lastFavoriteMusicId, int pageSize) {
        return new BizTemplate<DownloadFavoriteMusicResponse>(getClass().getSimpleName() + ".getUserData") {
            @Override
            protected void checkParams() throws VinciException {
                if (userId <= 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "userId小于等于0", "userId必须大于0");
                }
                if (lastFavoriteMusicId < 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "lastFavoriteMusicId小于0", "lastFavoriteMusicId不能小于0");
                }
                if (pageSize <= 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "pageSize小于等于0", "pageSize必须大于0");
                }
            }

            @Override
            protected DownloadFavoriteMusicResponse process() throws Exception {
                DownloadFavoriteMusicResponse response = new DownloadFavoriteMusicResponse();

                List<UserFavoriteMusic> list = favoriteDataOperator.getUserData(userId, lastFavoriteMusicId, pageSize);
                for (UserFavoriteMusic music : list) {
                    music.setIsFavorite(true);
                }

                response.setData(list);

                return response;
            }
        }.execute();
    }

    private HashMap<Long, HashMap<String, MusicFeedRelation>> getRelationMap(long userId, List<UserFavoriteMusic> list) {
        List<MusicFeedRelation> relationList = musicFeedRelationMapper.getData(userId, list);
        HashMap<Long, HashMap<String, MusicFeedRelation>> map = new HashMap<Long, HashMap<String, MusicFeedRelation>>();
        for (MusicFeedRelation musicFeedRelation : relationList) {
            HashMap<String, MusicFeedRelation> tempMap = map.get(musicFeedRelation.getSongId());
            if (tempMap == null) {
                tempMap = new HashMap<String, MusicFeedRelation>(3);
                map.put(musicFeedRelation.getSongId(), tempMap);
            }
            tempMap.put(musicFeedRelation.getSongType(), musicFeedRelation);
        }
        return map;
    }

    @Transactional
    public boolean updateData(final List<ClientUserData> list) {
        return new BizTemplate<Boolean>(getClass().getSimpleName() + ".updateData") {
            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected Boolean process() throws Exception {
                List<UserFavoriteMusic> insertList = new ArrayList<UserFavoriteMusic>();
                List<UserFavoriteMusic> deleteList = new ArrayList<UserFavoriteMusic>();

                long userId = list.get(0).getRealUserId();

                for (ClientUserData data : list) {
                    try {
                        if (!StringUtils.isEmpty(data.getData())) {
                            UserFavoriteMusic music = JsonUtils.decode(data.getData(), UserFavoriteMusic.class);
                            if (music != null) {
                                music.setUserId(data.getRealUserId());
                                if (data.getIsDelete()) {
                                    deleteList.add(music);
                                } else if (music.getIsFavorite()) {
                                    insertList.add(music);
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.info("parse data error, not FavoriteMusic, data is {}", data.getData());
                    }
                }

                int insert = 0;
                int delete = 0;

                if (!insertList.isEmpty()) {
                    insert = favoriteDataOperator.insertData(insertList);
                }

                if (!deleteList.isEmpty()) {
                    for (UserFavoriteMusic userFavoriteMusic : deleteList) {
                        favoriteDataOperator.deleteData(userFavoriteMusic);
                    }
                    delete = deleteList.size();
                }

                int delta = insert - delete;

                logger.info("update user favorite music data, userId={}, delta={}, insert={}, delete={}", userId, delta, insert, delete);

                if (delta != 0) {
                    userCountService.alterUserCollectionCount(userId, delta);
                }

                UserSettings userSettings = userLoginAndBindDeviceService.getUserSettings(userId);

                if (userSettings.getCollectToShare()) {
                    if (!insertList.isEmpty()) {
                        HashMap<Long, HashMap<String, MusicFeedRelation>> map = getRelationMap(userId, insertList);

                        Iterator<UserFavoriteMusic> it = insertList.iterator();
                        while (it.hasNext()) {
                            UserFavoriteMusic music = it.next();
                            if (map.containsKey(music.getSongId()) && map.get(music.getSongId()).containsKey(music.getSongType())) {
                                it.remove();
                            }
                        }

                        // 插入feed
                        List<MusicFeedRelation> relationList = new ArrayList<MusicFeedRelation>();
                        for (UserFavoriteMusic music : insertList) {
                            PublishFeedRequest request = new PublishFeedRequest();
                            request.setPageContent(JsonUtils.decode(music.getShareData()));

                            long feedId = feedService.publishFeed(userId, FeedType.FAVORITE_MUSIC, request);

                            MusicFeedRelation relation = new MusicFeedRelation();
                            relation.setUserId(music.getUserId());
                            relation.setSongId(music.getSongId());
                            relation.setSongType(music.getSongType());
                            relation.setFeedId(feedId);

                            relationList.add(relation);
                        }

                        if (!relationList.isEmpty()) {
                            musicFeedRelationMapper.insert(relationList);
                        }
                    }

                    if (!deleteList.isEmpty()) {
                        HashMap<Long, HashMap<String, MusicFeedRelation>> map = getRelationMap(userId, deleteList);

                        Iterator<UserFavoriteMusic> it = deleteList.iterator();
                        while (it.hasNext()) {
                            UserFavoriteMusic music = it.next();
                            if (!map.containsKey(music.getSongId()) || !map.get(music.getSongId()).containsKey(music.getSongType())) {
                                it.remove();
                            } else {
                                long feedId = map.get(music.getSongId()).get(music.getSongType()).getFeedId();
                                try {
                                    feedService.deleteFeed(userId, feedId);
                                } catch (VinciException e) {
                                    logger.warn("delete feed error,errorMessage:{}, userId:{}, feedId:{}", e.getErrorMsg(), userId, feedId);
                                }
                            }
                        }

                        if (!deleteList.isEmpty()) {
                            for (UserFavoriteMusic userFavoriteMusic : deleteList) {
                                musicFeedRelationMapper.delete(userFavoriteMusic);
                            }
                        }
                    }

                    logger.info("share user favorite music data, userId={}", userId);
                }

                return true;
            }
        }.execute();
    }

}
